//
//  RegexCategories.swift
//  SwiftKit
//
//  Created by LL on 2023/4/7.
//

import Foundation

public typealias RX = NSRegularExpression

public struct RxMatch {
    private let result: NSTextCheckingResult
    private let original: NSString
    
    let value: NSString
    let range: NSRange
    
    init(result: NSTextCheckingResult, original: NSString) {
        self.result = result
        self.original = original
        self.value = original.rxSubstring(with: result.range) ?? ""
        self.range = result.range
    }
    
    
    func range(_ index: Int) -> NSRange? {
        if index >= 0 && index < result.numberOfRanges {
            return result.range(at: index)
        }
        return nil
    }
    
    func range(_ name: String) -> NSRange? {
        let range = result.range(withName: name)
        if range.location == NSNotFound && range.length == 0 {
            return nil
        }
        return range
    }
    
    func value(_ index: Int) -> NSString? { original.rxSubstring(with: self.range(index)) }
    func value(_ name: String) -> NSString? { original.rxSubstring(with: self.range(name)) }
}


public extension NSRegularExpression {
    convenience init(_ text: String, _ options: NSRegularExpression.Options = []) throws { try self.init(pattern: text, options: options) }
    convenience init(_ text: NSString, _ options: NSRegularExpression.Options = []) throws { try self.init(pattern: String(text), options: options) }
    
    
    /// 如果字符串与正则表达式匹配，则返回true。
    func isMatch(_ text: NSString) -> Bool { self.firstRange(text) != nil }
    func isMatch(_ text: String) -> Bool { self.firstRange(text) != nil }
    
    
    /// 获取第1个匹配区间。
    func firstRange(_ text: NSString) -> NSRange? { self.firstMatch(in: String(text), range: text.rxRangeOfAll)?.range }
    func firstRange(_ text: String) -> NSRange? { self.firstMatch(in: text, range: text.rxRangeOfAll)?.range }
    
    
    /// 获取第1个匹配字符串。
    func firstValue(_ text: NSString) -> NSString? { text.rxSubstring(with: self.firstRange(text)) }
    func firstValue(_ text: String) -> NSString? { text.rxSubstring(with: self.firstRange(text)) }
    
    
    /// 获取所有匹配字符串。
    func values(_ text: NSString) -> [NSString] {
        var matches: [NSString] = []
        
        self.enumerateMatches(in: String(text), range: text.rxRangeOfAll) { result, _, _ in
            guard let result = result else { return }
            if let match = text.rxSubstring(with: result.range) {
                matches.append(match)
            }
        }
        
        return matches
    }
    func values(_ text: String) -> [NSString] { self.values(NSString(string: text)) }
    
    
    /// 获取第1个匹配对象。
    func firstMatch(_ text: NSString) -> RxMatch? {
        var match: RxMatch?
        self.enumerateMatches(in: String(text), range: text.rxRangeOfAll) { result, _, stop in
            guard let result = result else { return }
            match = RxMatch(result: result, original: text)
            stop.pointee = true
        }
        return match
    }
    func firstMatch(_ text: String) -> RxMatch? { self.firstMatch(NSString(string: text)) }
    
    
    /// 获取所有匹配对象。
    func matches(_ text: NSString) -> [RxMatch] {
        var results: [RxMatch] = []
        self.enumerateMatches(in: String(text), range: text.rxRangeOfAll) { result, _, _ in
            guard let result = result else { return }
            results.append(RxMatch(result: result, original: text))
        }
        return results
    }
    func matches(_ text: String) -> [RxMatch] { self.matches(NSString(string: text)) }
    
    
    /// 枚举所有匹配对象。
    func enumerateMatches(_ text: NSString, _ handler: (_ result: RxMatch) -> Void) {
        self.enumerateMatches(in: String(text), range: text.rxRangeOfAll) { result, _, _ in
            guard let result = result else { return }
            autoreleasepool {
                handler(RxMatch(result: result, original: text))
            }
        }
    }
    func enumerateMatches(_ text: String, _ handler: (_ result: RxMatch) -> Void) { self.enumerateMatches(NSString(string: text), handler) }
    
    
    /// 使用模板字符串替换所有匹配项。
    /// ```
    /// RX("ruf+").replace("ruf ruff!", template: "move") => "move move!"
    /// ```
    func replace(_ text: NSString, _ template: NSString) -> NSString {
        let mutableString = NSMutableString(string: text)
        self.replaceMatches(in: mutableString, range: mutableString.rxRangeOfAll, withTemplate: String(template))
        return NSString(string: mutableString)
    }
    func replace(_ text: String, template: String) -> NSString { self.replace(NSString(string: text), NSString(string: template)) }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replace(_ text: NSString, _ handler:((_ value: NSString) -> NSString)) -> NSString {
        return self.replace(text) { (_ match: RxMatch) in
            return handler(match.value)
        }
    }
    func replace(_ text: String, _ handler:((_ value: NSString) -> NSString)) -> NSString { self.replace(NSString(string: text), handler) }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replace(_ text: NSString, _ handler:((_ match: RxMatch) -> NSString)) -> NSString {
        let mutableString = NSMutableString(string: text)
        for match in self.matches(text).reversed() {
            let template = handler(match)
            mutableString.replaceCharacters(in: match.range, with: String(template))
        }
        return NSString(string: mutableString)
    }
    func replace(_ text: String, _ handler:((_ match: RxMatch) -> NSString)) -> NSString { self.replace(NSString(string: text), handler) }
}


public extension NSString {
    /// 等于直接调用`try? NSRegularExpression(pattern: self)`。
    var toRx: NSRegularExpression? { try? RX(self) }
    
    
    /// 等于直接调用`try? NSRegularExpression(pattern: self, options: options)`。
    func toRx(_ options: NSRegularExpression.Options) -> NSRegularExpression? { try? RX(self, options) }
    
    
    /// 如果字符串与正则表达式匹配，则返回true。
    func isMatch(_ regex: NSRegularExpression) -> Bool { regex.isMatch(self) }
    
    
    /// 获取第1个匹配区间。
    func firstRange(_ regex: NSRegularExpression) -> NSRange? { regex.firstRange(self) }
    
    
    /// 获取第1个匹配字符串。
    func firstValue(_ regex: NSRegularExpression) -> NSString? { regex.firstValue(self) }
    
    
    /// 获取所有匹配字符串。
    func values(_ regex: NSRegularExpression) -> [NSString] { regex.values(self) }
    
    
    /// 获取第1个匹配对象。
    func firstMatch(_ regex: NSRegularExpression) -> RxMatch? { regex.firstMatch(self) }
    
    
    /// 获取所有匹配对象。
    func matches(_ regex: NSRegularExpression) -> [RxMatch] { regex.matches(self) }
    
    
    /// 枚举所有匹配对象。
    func enumerateMatches(_ regex: NSRegularExpression, _ handler: (_ result: RxMatch) -> Void) { regex.enumerateMatches(self, handler) }
    
    
    /// 使用模板字符串替换所有匹配项。
    /// ```
    /// "ruf ruff!".replacingMatch(regex, "move") => "move move!"
    /// ```
    func replacingMatch(_ regex: NSRegularExpression, _ template: NSString) -> NSString { regex.replace(self, template) }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replacingMatch(_ regex: NSRegularExpression, _ handler:((_ value: NSString) -> NSString)) -> NSString { regex.replace(self, handler) }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replacingMatch(_ regex: NSRegularExpression, _ handler:((_ match: RxMatch) -> NSString)) -> NSString { regex.replace(self, handler) }
}


public extension NSMutableString {
    /// 使用模板字符串替换所有匹配项。
    func replaceMatch(_ regex: NSRegularExpression, _ template: NSString) {
        regex.replaceMatches(in: self, range: self.rxRangeOfAll, withTemplate: String(template))
    }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replaceMatch(_ regex: NSRegularExpression, _ handler:((_ value: NSString) -> NSString)) {
        self.replaceMatch(regex) { (_ match: RxMatch) in
            return handler(match.value)
        }
    }
    
    
    /// 该方法自由度最高，当你需要将不同的值修改为不同字符串时，例如将 "1" 修改为 "one"、"2" 修改为 "two"；它还能控制是否需要修改。
    func replaceMatch(_ regex: NSRegularExpression, _ handler:((_ match: RxMatch) -> NSString)) {
        for match in regex.matches(NSString(string: self)).reversed() {
            self.replaceCharacters(in: match.range, with: String(handler(match)))
        }
    }
}


fileprivate extension NSString {
    var rxRangeOfAll: NSRange { NSRange(location: 0, length: self.length) }
    func rxSubstring(with range: NSRange?) -> NSString? {
        guard let range = range else { return nil }
        if range.location < 0 || range.length < 0  { return nil }
        if NSMaxRange(range) > self.length { return nil }
        return self.substring(with: range) as NSString
    }
}
